(in-package :gwee)

(defclass scroller (widget)
  ((knob-position :initform 0 :initarg :knob-position :accessor scroller-knob-position)
   (knob-length :initform 20 :initarg :knob-length :accessor scroller-knob-length)
   (knob-proportion :initform 1 :initarg :knob-proportion :accessor scroller-knob-proportion)
   (knob-offset :initform nil :accessor scroller-knob-offset)
   (scroll-view :initarg :scroll-view :accessor scroller-scroll-view)
   (max :initform 0 :initarg max :accessor scroller-max)
   (callback :initform nil :initarg :callback :accessor scroller-callback
	     :documentation "This function is called any time the scroller knob moves.")))

(defclass vertical-scroller (scroller)
  ()
  (:default-initargs
   :width 15))

(defclass horizontal-scroller (scroller)
  ()
  (:default-initargs
   :height 15))

(defmethod scroll-to ((view scroller) pos)
  (with-slots (knob-position knob-proportion knob-length callback) view
    (setf knob-position (truncate (min (max pos 0) (* (- (gwee:view-width view) knob-length)
                                                      knob-proportion)))
          (view-needs-update-p view) t)
    (when callback
      (funcall callback view))))

(defmethod scroller-move-knob ((view scroller) amt)
  (scroll-to view (+ (scroller-knob-position view) amt)))

(defmethod mouse-press-event ((view vertical-scroller) button x y)
  (declare (ignore button x))
  ;; for now just center the knob at that location.
  (setf (scroller-knob-position view) y
	(view-needs-update-p view) t)
  (when (scroller-callback view)
    (funcall (scroller-callback view) view)))

(defmethod mouse-release-event ((view scroller) button x y)
  (declare (ignore button x y))
  (ungrab-mouse view))

(defmethod mouse-press-event ((view horizontal-scroller) button x y)
  (declare (ignore button y))
  (unless (disabled-p view)
    (with-slots (knob-position knob-proportion knob-offset knob-length callback) view
      (let ((p (truncate knob-position knob-proportion)))
        (if (<= p
                x
                (+ p knob-length))
            (progn
              (setf knob-offset (- p x))
              (grab-mouse view))
            (scroller-move-knob view
                                (* knob-proportion
                                   (if (< x p)
                                       (- knob-length)
                                       knob-length))))))))

(defmethod mouse-motion-event ((view horizontal-scroller) state x y xrel yrel)
  (declare (ignore xrel y yrel))
  (unless (disabled-p view)
    (when (and state
               (eq (first (top-mouse-grabs *top-view*)) view))
      (with-slots (knob-position knob-proportion knob-length knob-offset callback) view
        (setf knob-position (truncate (* (min (max (+ x knob-offset)
                                                   0)
                                              (- (view-width view) knob-length 1))
                                         knob-proportion))
              (view-needs-update-p view) t)
        (when callback
          (funcall callback view))))))

(defun draw-knob (v x y w h)
  (draw-rectangle v x y w h :filled t :color (gwee:gray 220))
  (draw-hline v x (+ x w) y :color (gwee:gray 240))
  (draw-vline v (+ x w) y (+ y h) :color (gwee:gray 240))
  (draw-hline v x (+ x w) (+ y h) :color (gwee:gray 190))
  (draw-vline v x y (+ y h) :color (gwee:gray 190)))

(defmethod draw-view ((view horizontal-scroller))
  (with-slots (knob-position knob-length knob-proportion) view
    (sdl:draw-box-* (view-cache-top-x view) (view-cache-top-y view)
                    (view-width view) (view-height view)
                    :color (gray 150))
    (unless (disabled-p view)
      (draw-knob view (truncate knob-position knob-proportion) 0 knob-length (1- (view-height view))))))

(defmethod draw-view ((view vertical-scroller))
  (with-slots (knob-position knob-length knob-proportion) view
    (sdl:draw-box-* (view-cache-top-x view) (view-cache-top-y view)
                    (view-width view) (view-height view)
                    :color (gray 150))
    (draw-knob view 0 (truncate knob-position knob-proportion) (1- (view-width view)) knob-length)))

;; (defclass scroll-view (view)
;;   ((vscroller :initform nil :accessor scroll-view-vscroller)
;;    (hscroller :initform nil :accessor scroll-view-hscroller)
;;    (content-view :initarg :content-view :accessor scroll-view-content-view)))

;; (defmethod (setf view-subviews) (value (view scroll-view))
;;   (warn "You can't change the subviews of a scroll-view"))

;; (defmethod initialize-instance :after ((obj scroll-view) &key vertical-scroll-p horizontal-scroll-p)
;;   (when vertical-scroll-p
;;     (setf (scroll-view-vscroller obj) (make-instance 'vertical-scroller :height (view-height obj) :max (view-height obj) :parent obj)))
;;   (when horizontal-scroll-p
;;     (setf (scroll-view-hscroller obj) (make-instance 'horizontal-scroller :width (view-width obj) :max (view-width obj) :parent obj)))
;;   (setf (view-parent (scroll-view-content-view obj)) obj))
